<?php

namespace app\common\model\xilujob;

use app\common\library\Auth;
use app\common\library\xilujob\Geohash;
use app\common\model\User;
use think\Db;
use think\db\Query;
use think\Exception;
use think\Log;
use think\Model;
use traits\model\SoftDelete;
use function fast\array_get;

class Job extends Model
{

    use SoftDelete;

    const TYPE_FULLTIME = 1;
    const TYPE_PARTTIME = 2;

    const STATUS_DISABLED = 0;//下架
    const STATUS_ENABLED = 1;//上架
    const STATUS_AUDITING = 2;//待审核
    const STATUS_FAILED = 3;//未过审

    const SALARY_TYPE_NEGOTIABLE = 0;//面议
    const SALARY_TYPE_HOURLY = 1;//时薪
    const SALARY_TYPE_DAILY = 2;//日薪
    const SALARY_TYPE_MONTHLY = 3;//月薪

    // 表名
    protected $name = 'xilujob_job';
    
    // 自动写入时间戳字段
    protected $autoWriteTimestamp = 'int';

    // 定义时间戳字段名
    protected $createTime = 'createtime';
    protected $updateTime = 'updatetime';
    protected $deleteTime = 'deletetime';

    // 追加属性
    protected $append = [
        'type_text',
        'refreshtime_text',
        'status_text',
        'black_text',
        'salary_text'
    ];

    protected static function init() {
        static::beforeInsert(function(Job $job){
            $job->refreshtime = time();
            $job->refresh_date = date('Y-m-d');
        });
        static::beforeUpdate(function(Job $job){
            if(isset($job->getChangedData()['status'])&&$job->status==Job::STATUS_ENABLED) {
                $job->refreshtime = time();
                $job->refresh_date = date('Y-m-d');
            }
        });
        $updateJobCount = function(Job $job) {
            try {
                $tablePrefix = config('database.prefix');
                //更新发布企业
                Db::execute("update {$tablePrefix}xilujob_company_statistics set job_count=(select count(*) from {$tablePrefix}xilujob_job where publisher_id={$job->publisher_id} and status='1') where company_id={$job->publisher_id}");
            }catch (\Exception $e) {
                Log::error($e->getTraceAsString());
            }
        };
        static::afterUpdate($updateJobCount);
        static::afterDelete($updateJobCount);
    }

    public function getTypeList()
    {
        return ['1' => __('全职'), '2' => __('兼职')];
    }

    public function getStatusList()
    {
        return ['0' => __('Status 0'), '1' => __('Status 1'), ' 2' => __('Status  2'), ' 3' => __('Status  3')];
    }

    public function getBlackList()
    {
        return ['0' => __('Black 0'), '1' => __('Black 1')];
    }



    public function getTypeTextAttr($value, $data)
    {
        $value = $value ? $value : (isset($data['type']) ? $data['type'] : '');
        $list = $this->getTypeList();
        return isset($list[$value]) ? $list[$value] : '';
    }


    public function getRefreshtimeTextAttr($value, $data)
    {
        $value = $value ? $value : (isset($data['refreshtime']) ? $data['refreshtime'] : '');
        return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
    }


    public function getStatusTextAttr($value, $data)
    {
        $value = $value ? $value : (isset($data['status']) ? $data['status'] : '');
        $list = $this->getStatusList();
        return isset($list[$value]) ? $list[$value] : '';
    }


    public function getBlackTextAttr($value, $data)
    {
        $value = $value ? $value : (isset($data['black']) ? $data['black'] : '');
        $list = $this->getBlackList();
        return isset($list[$value]) ? $list[$value] : '';
    }

    /**
     * 薪资 xxx-xxx 元/时日月
     */
    public function getSalaryTextAttr($value, $data) {
        try {
            if($this->salary_type==self::SALARY_TYPE_NEGOTIABLE) {
                return '面议';
            }
            $per = $this->salary_type==self::SALARY_TYPE_HOURLY?'/时':($this->salary_type==self::SALARY_TYPE_DAILY?'/日':'/月');
            if($this->salary_min>0 && $this->salary_max>0) {
                return sprintf('%s-%s元'.$per, $this->salary_min, $this->salary_max);
            }else if($this->salary_min==0) {
                return sprintf('%s元以下', $this->salary_max);
            }else if($this->salary_max==0) {
                return sprintf('%s元以上', $this->salary_min);
            }else {
                return '';
            }
        }catch (\Exception $e) {
            Log::error($e->getMessage()."\n".$e->getTraceAsString());
            return '';
        }

    }

    /**
     * 关联查询 JobCategory
     * @return \think\model\relation\BelongsTo
     */
    public function jobCategory() {
        return $this->belongsTo('JobCategory','job_category_id','id',[],'LEFT')->setEagerlyType(0);
    }

    public function enterpriseinfo() {
        return $this->belongsTo('EnterpriseInfo', 'publisher_id','company_id')->setEagerlyType(0);
    }

    public function province() {
        return $this->belongsTo('Area','province_id');
    }
    public function city() {
        return $this->belongsTo('Area','city_id');
    }

    public function district() {
        return $this->belongsTo('Area','district_id');
    }

    public function town() {
        return $this->belongsTo('Area','town_id');
    }

    public function benefits() {
        return $this->belongsToMany('Benefit',JobBenefit::class,'benefit_id','job_id');
    }

    public function jobInfo() {
        return $this->hasOne('JobInfo', 'job_id','id');
    }

    public function locations() {
        return $this->hasMany('JobLocation', 'job_id');
    }

    public function workExperience() {
        return $this->belongsTo('WorkExperience','work_experience_id','id',[],'LEFT');
    }
    public function educationLevel() {
        return $this->belongsTo('EducationLevel','education_level_id', 'id', [], 'LEFT');
    }
    /*企业端职位预览*/
    public function user() {
        return $this->belongsTo(User::class,'user_id','id',[],'LEFT')->setEagerlyType(0);
    }

    //读取jobInfo的属性
    public function getResponsibilityAttr() {
        return $this->job_info->responsibility;
    }
    public function getRequirementAttr() {
        return $this->job_info->requirement;
    }
    public function getEnvironmentImagesAttr() {
        return $this->job_info->environment_images;
    }
    public function getContactPersonAttr() {
        return $this->job_info->contact_person;
    }
    public function getContactPhoneAttr() {
        return $this->job_info->contact_phone;
    }
    public function getContactEmailAttr() {
        return $this->job_info->contact_email;
    }
    public function getFailedReasonAttr() {
        return $this->job_info->failed_reason;
    }

    /**
     * 获取企业发布职位数可用次数
     * @param $companyId
     * @param $type
     * @return int
     */
    public static function getAvailableNum($companyId,$type) {
        $enterpriseinfo = EnterpriseInfo::field('id,job_num_limit,job_refresh_num')->where('company_id', $companyId)->find();
        if(!$enterpriseinfo) {
            return 0;
        }
        if($type == 'job_publish'){
            $job_publish_num = Config::getdatas("job_publish_num") ?? 0;
            if($job_publish_num > 0) {
                // 有免费次数 , 判定是否还有剩余
                $todayNum = JobLog::where('company_id',$companyId)
                    //->whereTime('createtime','m')
                    ->count();
                $freeNum = $job_publish_num > $todayNum ? $job_publish_num - $todayNum : 0;
            }else {
                $freeNum = 0;
            }
            $return = intval($freeNum + $enterpriseinfo->job_num_limit);
        }else{
            $job_refresh_num = Config::getdatas("job_refresh_num") ?? 0;
            if($job_refresh_num > 0) {
                // 有免费次数 , 判定是否当日还有剩余
                $todayNum = JobRefreshLog::where('company_id',$companyId)
                    //->whereTime('createtime','m')
                    ->count();
                $freeNum = $job_refresh_num > $todayNum ? $job_refresh_num - $todayNum : 0;
            }else {
                $freeNum = 0;
            }
            $return = intval($freeNum + $enterpriseinfo->job_refresh_num);
        }
        return $return;
    }
    /**
     * @param array $data benefit_ids: 1,2,3;
     * @return
     */
    public static function addJob($data) {
        $validator = new \app\common\validate\xilujob\Job([],[],$data);
        if(!$validator->scene('add')->check($data)) {
            throw new Exception($validator->getError());
        }
        $data['responsibility'] = self::hide_contact($data['responsibility']);

        $enterpriseinfo = EnterpriseInfo::field('id,job_num_limit')->where('company_id', $data['publisher_id'])->find();
        if(!$enterpriseinfo) {
            throw new Exception(__('no record'));
        }
        $job_publish_num = Config::getdatas("job_publish_num") ?? 0;
        if($job_publish_num > 0) {
            // 有免费次数 , 判定是否当日还有剩余
            $todayNum = JobLog::where('company_id',$data['publisher_id'])
                ->count();
            $freeNum = $job_publish_num > $todayNum ? $job_publish_num - $todayNum : 0;
        }else {
            $freeNum = 0;
        }
        if($freeNum <= 0 && $enterpriseinfo->job_num_limit <= 0) {
            throw new Exception("您购买的职位发布数已用尽，请前往购买");
        }
        try {
            $job = new Job();
            if($data['publisher_type']== XilujobUser::GROUP_COMPANY) {
                $data['direct'] = 1;
                $data['shop'] = 0;
            } else {
                $data['shop'] = 1;
                $data['direct'] = 0;
            }
            if(get_addon_config('xilujob')['job_audit_switch']) {
                //需要审核
                $data['status'] = Job::STATUS_AUDITING;
            }else {
                //直接过审
                $data['status'] = Job::STATUS_ENABLED;
            }
            $result = $job->save(array_intersect_key($data, array_flip((array)  ['user_id',
                'publisher_id', 'publisher_type', 'type', 'job_name', 'job_category_id', 'city_id', 'district_id', 'province_id',
                'direct','shop','in_hurry','red_packet', 'red_packet_instruction', 'work_experience_id', 'education_level_id', 'salary_type',
                'salary_min', 'salary_max', 'num', 'status'
            ])));
            if($result===false) {
                throw new Exception($job->getError());
            }
            $jobInfo = new JobInfo();
            $data['job_id'] = $job->id;
            $result = $jobInfo->save(array_intersect_key($data, array_flip((array) [
                'job_id','responsibility','requirement','environment_images','contact_person','contact_phone','contact_email'
            ])));
            if($result===false) {
                throw new Exception($jobInfo->getError());
            }
            $benefitIds = array_get($data,'benefit_ids');
            if($benefitIds) {
                $benefitIds = is_array($benefitIds) ? $benefitIds : explode(',', $benefitIds);
                foreach ($benefitIds as &$benefitId) {
                    $benefitId = ['job_id'=>$job->id, 'benefit_id'=>$benefitId];
                }
                $cb = new JobBenefit();
                $cb->saveAll($benefitIds);
            }
            $locations = array_get($data, 'locations');
            foreach($locations as $location) {
                $jobLocation = new JobLocation();
                $location['job_id'] = $job->id;
                unset($location['id']);

                $lat = array_get($location,'lat');
                $lng = array_get($location,'lng');
                if($lat || $lng){
                    $geohashTool = new \app\common\library\xilujob\Geohash();
                    $geohash = $geohashTool->encode($lat, $lng, 8);
                    $location['geo_status'] = JobLocation::GEO_STATUS_PARSED;
                    $location['geohash'] = $geohash;
                }

                $result = $jobLocation->save($location);
                if($result===false) {
                    throw new Exception($jobLocation->getError());
                }
            }
            //职位添加日志
            $result = JobLog::record($data['user_id'],$job);
            //减去职位发布数
            if($freeNum <= 0) {
                $enterpriseinfo->save(['job_num_limit'=>Db::raw('job_num_limit-1')]);
            }
            return $job;
        }catch(\Exception $e) {
            Log::error($e->getMessage()."\n".$e->getTraceAsString());
            throw $e;
        }
    }

    /**
     * @param Job|int $job
     * @param array $data benefit_ids: 1,2,3;
     * @return $job
     */
    public static function editJob($job, $data) {
        if(!$job instanceof Job) {
            $job = Job::get($job);
            if(!$job) {
                throw new Exception(__('no record'));
            }
        }
        $validator = new \app\admin\validate\xilujob\Job([],[],$data);
        if(!$validator->scene('edit')->check($data)) {
            throw new Exception($validator->getError());
        }
        $data['responsibility'] = self::hide_contact($data['responsibility']);
        if(get_addon_config('xilujob')['job_audit_switch']) {
            //需要审核
            $data['status'] = Job::STATUS_AUDITING;
        }else {
            //直接过审
            $data['status'] = Job::STATUS_ENABLED;
        }
        try {
            $result = $job->save(array_intersect_key($data, array_flip((array) [
                'type', 'job_name', 'job_category_id', 'city_id', 'district_id', 'province_id', 'in_hurry', 'red_packet', 'red_packet_instruction','status',
                'work_experience_id', 'education_level_id', 'salary_type', 'salary_min', 'salary_max', 'num'
            ])));
            if($result===false) {
                throw new Exception($job->getError());
            }
            $jobInfo = JobInfo::get(['job_id'=>$job->id]);
            $data['job_id'] = $job->id;
            $data['audittime'] = 0;
            $result = $jobInfo->save(array_intersect_key($data, array_flip((array) [
                'job_id','responsibility','requirement','environment_images','contact_person','contact_phone','contact_email','audittime'
            ])));
            if($result===false) {
                throw new Exception($jobInfo->getError());
            }
            $benefitIds = array_get($data,'benefit_ids');
            if($benefitIds) {
                $insertBenefits = [];
                $benefitIds = is_array($benefitIds) ? $benefitIds : explode(',', $benefitIds);

                JobBenefit::whereNotIn('benefit_id', $benefitIds)->where('job_id', $job->id)->delete();

                foreach ($benefitIds as &$benefitId) {
                    if(JobBenefit::where('job_id',$job->id)->where('benefit_id',$benefitId)->count()<1)
                        $insertBenefits[] = ['job_id'=>$job->id, 'benefit_id'=>$benefitId];
                }

                if($insertBenefits) {
                    $cb = new JobBenefit();
                    $cb->saveAll($insertBenefits);
                }
            }else {
                JobBenefit::where('job_id', $job->id)->delete();
            }
            $locations = array_get($data, 'locations');
            $locationIds = [];
            foreach($locations as $location) {
                if(isset($location['company_address_id']) && $location['company_address_id']) {
                    $jobLocation = JobLocation::get(['company_address_id'=>$location['company_address_id'],'job_id'=>$job->id]);
                    if(!$jobLocation){
                        $jobLocation = new JobLocation();
                    }
                }else if(isset($location['id']) && $location['id']){
                    $jobLocation = JobLocation::get(['id'=>$location['id']]);
                    if(!$jobLocation || $jobLocation->job_id!=$job->id)
                        continue;
                }else{
                    $jobLocation = new JobLocation();
                }
                $lat = array_get($location,'lat');
                $lng = array_get($location,'lng');
                if($lat || $lng){
                    $geohashTool = new \app\common\library\xilujob\Geohash();
                    $geohash = $geohashTool->encode($lat, $lng, 8);
                    $location['geo_status'] = JobLocation::GEO_STATUS_PARSED;
                    $location['geohash'] = $geohash;
                }
                $location['job_id'] = $job->id;
                $result = $jobLocation->save($location);
                if($result===false) {
                    throw new Exception($jobLocation->getError());
                }
                $locationIds[] = $jobLocation->id;
            }
            //halt($locationIds);
            JobLocation::where(['job_id' => $job->id, 'id'=>['not in',$locationIds]])->delete();
            return $job;
        }catch(\Exception $e) {
            Log::error($e->getMessage()."\n".$e->getTraceAsString());
            throw new Exception($e->getMessage());
        }
    }

    public static function delJob($job) {
        if(!$job instanceof Job) {
            $job = Job::get($job);
            if(!$job) {
                throw new Exception(__('no record'));
            }
        }
        try {
            Db::startTrans();
            $job->delete();
            JobApply::where('job_id', $job->id)->delete();
            //删除报名记录, 职位收藏
            //JobSignup::where('job_id', $job->id)->delete();
            UserCollection::where('collection_id', $job->id)->where('collection_type', UserCollection::TYPE_JOB)->delete();
            //以下暂不删除, 因没有入口访问不影响功能使用且没有软删除
//            JobInfo::where('id', $job->id)->delete();
//            JobLocation::where('job_id', $job->id)->delete();
//            JobBenefit::where('job_id', $job->id)->delete();
            Db::commit();
            return $job;
        }catch(\Exception $e) {
            Log::error($e->getMessage()."\n".$e->getTraceAsString());
            Db::rollback();
           throw $e;
        }
    }

    /**
     * 公司上架职位
     * @param $job
     * @return $this
     */
    public static function switchOnJob($job) {
        if(!$job instanceof Job) {
            $job = Job::get($job);
        }
        if($job->status == self::STATUS_ENABLED) {
            return $job;
        }
        if(!in_array($job->status, [self::STATUS_DISABLED])) {
            throw new Exception('职位无法发布');
        }
        try {
            Db::transaction(function () use ($job) {
                $status = get_addon_config('xilujob')['job_audit_switch'] ? ($job->job_info->audittime ? self::STATUS_AUDITING:self::STATUS_ENABLED) : self::STATUS_ENABLED;
                $ret = $job->save(['status'=>$status,'publish_time'=>time(), 'publish_count'=>Db::raw('publish_count+1')]);
                if($ret===false) {
                    throw new Exception($job->getError());
                }
            });
            return $job;
        }catch (\Exception $e) {
            Log::error($e->getMessage()."\n".$e->getTraceAsString());
            throw $e;
        }
    }

    /**
     * 公司下架、取消审核职位
     * @param $job
     * @return $this
     */
    public static function switchOffJob($job) {
        if(!$job instanceof Job) {
            $job = Job::get($job);
        }
        if($job->status==self::STATUS_DISABLED) {
            return $job;
        }
        if(!in_array($job->status, [self::STATUS_ENABLED, self::STATUS_AUDITING, self::STATUS_FAILED])) {
            throw new Exception('状态无法变更');
        }
        try {
            Db::transaction(function () use ($job) {
                $ret = $job->save(['status'=>self::STATUS_DISABLED]);
                if($ret===false) {
                    throw new Exception($job->getError());
                }
            });
            return $job;
        }catch (\Exception $e) {
            Log::error($e->getMessage()."\n".$e->getTraceAsString());
            throw $e;
        }
    }

    /**
     * 热门工作
     * @param $user
     * @param array $params page: ; pagesize: ;
     * @param int $fill
     * @return array
     */
    public static function recommendJobs($user, $params, $fill=null) {
        if($user && !$user instanceof User) {
            $user = User::get($user);
            if(!$user) {
                throw new Exception(__('invalid arguments'));
            }
        }

        $page = abs(intval(array_get($params,'page')));
        $page = $page > 0 ? $page : 1;
        $pagesize = abs(intval(array_get($params, 'pagesize', 10)));
        $pagesize = $pagesize>0 ? $pagesize : 10;
        $fields = 'job.id,publisher_id,type,job_name,top,job_category_id,city_id,district_id,town_id,in_hurry,direct,shop,red_packet,'.
            'red_packet_instruction,work_experience_id,education_level_id,salary_type,salary_min,salary_max,refresh_date';
        $query = Job::alias('job')->where('status', Job::STATUS_ENABLED)
            ->where('black',0);
        if($cityId = array_get($params, 'city_id')) {
            $query->where('job.city_id', $cityId);
        }
        if($user) {
            $query->where('publisher_id','not in', function($query) use($user) {
                $query->name('xilujob_user_blacklist_company')->where('user_id', $user->id)->field('company_id');
            });
            //$resume = Resume::getUserResume($user->id);
            $resume = Resume::where('user_id',$user->id)->find();
            if($resume) {
                if($resume->job_intention) {
                    $fav_category = array_column(collection($resume->job_intention)->toArray(),'fav_category');
                    $map = [];
                    if($fav_category){
                        $fav_second_category_ids = array_column(collection($fav_category)->toArray(),'pid');
                        $paths = JobCategory::where('id','in',$fav_second_category_ids)->column('path');

                       foreach ($paths as $path){
                           $map[] = "category.`path` like '$path%'";
                       }
                    }
                    //halt(implode(' OR ',$map));
                    // 二级分类
                    //$category = JobCategory::get($resume->job_intention[0]->fav_category->pid);
                    $query->join('XilujobJobCategory category','job.job_category_id=category.id');
                    $query->where(implode(' OR ',$map));

                }
            }
        }
        $jobs = $query
            ->order('top','desc')
            ->order('refresh_date', 'desc')
            ->order('apply_count', 'desc');
        if($user) {
            $sub1 = Job::alias('job')->field($fields)
                ->join('xilujob_user_recommend_job r','job.id=r.job_id')
                ->where('job.user_id', $user->id)
                ->order('weigh','desc')
                ->buildSql();
            $sub2 = $jobs->field($fields)->buildSql();
            $total = (new Job())->query("select count(*) as count from ($sub1 union $sub2) as t")[0]['count'];
            $jobs = (new Job())->query("select * from ($sub1 union $sub2) as t limit ".($page-1).",$pagesize");
            foreach($jobs as &$job) {
                $job = new Job($job);
                $job->relationQuery([
                    'city'=>function(Query $query){$query->withField('id,name,shortname');},
                    'district'=>function(Query $query){$query->withField('id,name,shortname');},
                    'town'=>function($query){$query->withField('id,name,shortname');},
                    'work_experience'=>function(Query $query){$query->withField('id,name');},
                    'education_level'=>function(Query $query){$query->withField('id,name');},
                    'benefits'=>function(Query $query){$query->withField('id,name');},
                    'enterpriseinfo'=>function(Query $query){$query->withField('id,company_name,logo,full_name');}
                ]);
            }
        }else {
            $jobs = $jobs->field(str_replace('job.id','id',$fields))->with([
                'city'=>function(Query $query){$query->withField('id,name,shortname');},
                'district'=>function(Query $query){$query->withField('id,name,shortname');},
                'town'=>function($query){$query->withField('id,name,shortname');},
                'work_experience'=>function(Query $query){$query->withField('id,name');},
                'education_level'=>function(Query $query){$query->withField('id,name');},
                'benefits'=>function(Query $query){$query->withField('id,name');},
                'enterpriseinfo'=>function(Query $query){$query->withField('id,company_name,logo,full_name');}
            ])->paginate([
                'list_rows' => $pagesize,
                'page' => $page
            ]);
            $total = $jobs->total();
            $jobs = $jobs->getCollection();
        }

        try {
            if ($fill && $total < $fill) {
                $num = $fill - $total;
                $ids = [];
                foreach ($jobs as $job) {
                    $ids[] = $job['id'];
                }
                $query = Job::whereNotIn('id', $ids);
                if ($cityId) {
                    $query->where('city_id', $cityId);
                }
                $query = $query->with([
                    'city' => function (Query $query) {
                        $query->withField('id,name,shortname');
                    },
                    'district' => function (Query $query) {
                        $query->withField('id,name,shortname');
                    },
                    'town' => function ($query) {
                        $query->withField('id,name,shortname');
                    },
                    'work_experience' => function (Query $query) {
                        $query->withField('id,name');
                    },
                    'education_level' => function (Query $query) {
                        $query->withField('id,name');
                    },
                    'benefits' => function (Query $query) {
                        $query->withField('id,name');
                    },
                    'enterpriseinfo' => function (Query $query) {
                        $query->withField('id,company_name,logo,full_name');
                    }
                ])->limit(0,$num)->select();
                $jobs = $query->merge($jobs);
            }
        }catch (\Exception $e) {

        }
        return ['jobs'=>$jobs, 'total'=>$total];
    }

    /**
     * 列表页获取
     * @param array $params
     * @return \think\Paginator
     */
    public static function searchJobs($params) {
        $fields = 'id,publisher_id,type,job_name,job_category_id,job.city_id,job.district_id,job.town_id,in_hurry,direct,shop,red_packet,'.
            'red_packet_instruction,work_experience_id,education_level_id,salary_type,salary_min,salary_max,refresh_date,job.top';
        $query = self::alias('job')->where('status', Job::STATUS_ENABLED)
            ->where('black',0)
            ->join('XilujobJobCategory category','job.job_category_id=category.id')
            ->join('xilujob_company_profile p', 'p.id=job.publisher_id','LEFT')
            ->where(function ($query){
                $query->whereNull('p.id')->whereOr('p.audit_status',1);
            });
        //首页分类
        if($cateType = array_get($params,'cate_type')) {
            switch ($cateType) {
                case 'labour':
                    //蓝领职位
                    $query->where('category.labour_job', 1);
                    break;
                case 'parttime':
                    //兼职职位
                    $query->where('type', Job::TYPE_PARTTIME);
                    break;
                case 'redpacket':
                    //红包招聘
                    $query->where('red_packet','>', 0);
                    break;
                case 'hurry':
                    //红包招聘
                    $query->where('in_hurry', 1);
                    break;
                case 'brand':
                    //名企大厂
                    $query->where('brand', 1);
                    break;
            }
        }

        //城市筛选
        if($cityId = array_get($params, 'city_id')) {
            $query->where('job.city_id', $cityId);
        }
        //区域筛选
        if($district_id = array_get($params,'district_id')) {
            $query->where('job.district_id', $district_id);
        }
        //镇筛选
//        if($townId = array_get($params,'town_id')) {
//            $query->where('job.town_id', $townId);
//        }
        //距离
        $distance = intval(array_get($params, 'distance', 0));//公里
        if($distance) {
            $pos = explode(',', array_get($params,'pos',''));
            $lng = array_get($pos,0);
            $lat = array_get($pos, 1);
            if($lng&&$lat) {
                //米
                if($distance) {
                    //限定数据为20公里附近的， 因最远的distance为10公里
                    $geohash = (new Geohash())->encode($lat, $lng,2);
                    $query->where('job.id', 'in', function(Query $subQuery) use ($lat, $lng, $geohash, $distance, $cityId) {
                        $subQuery->name('xilujob_job_location')->alias('l')
                            ->field("l.job_id")
                            ->where('geohash','like', "$geohash%")
                            ->whereRaw("ROUND(6378.138*2*ASIN(SQRT(POW(SIN(($lat*PI()/180-lat*PI()/180)/2),2)+COS($lat*PI()/180)*COS(lat*PI()/180)*POW(SIN(($lng*PI()/180-lng*PI()/180)/2),2)))*1000) < ".$distance*1000);
                        if($cityId) {
                            $subQuery->where('city_id', $cityId);
                        }
                    });
                }
            }
        }
        //分类
        if($categoryId = array_get($params, 'category_id')) {
            $category = JobCategory::get($categoryId);
            $query->where('category.path','like', $category->path.'%');
        }
        //薪资类型
        if($salaryType = array_get($params, 'salary_type')) {
            $query->where('salary_type', $salaryType);
        }
        $salaryMin = array_get($params, 'salary_min');
        $salaryMax = array_get($params, 'salary_max');
        //薪资下限
        if($salaryMin && $salaryMax){
            $query->where('salary_max','>=', $salaryMin)->where('salary_min','<=',$salaryMax);
        }else if($salaryMin){
            $query->where('salary_min','>=', $salaryMin);
        }else if($salaryMax){
            //薪资上限
            $query->where('salary_max','<=', $salaryMax);
        }
        if($scaleId = array_get($params, 'scale_id')) {
            $query->where('enterpriseinfo.company_scale_id', $scaleId);
        }
        //工作经验
        if($workExperienceId = array_get($params, 'work_experience_id')) {
            $query->where('work_experience_id', $workExperienceId);
        }
        //职位性质
        $type = array_get($params, 'type', '');
        if(in_array($type,[Job::TYPE_FULLTIME, Job::TYPE_PARTTIME])) {
            $query->where('type', $type);
        }
        //学历要求
        if($educationLevelId = array_get($params, 'education_level_id')) {
            $query->where('education_level_id', $educationLevelId);
        }
        //福利
        if($benefitIds = array_get($params, 'benefit_id')) {
            $query->where('job.id','in', function(Query $query) use ($benefitIds) {
                $query->name('xilujob_job_benefit_relation')->whereIn('benefit_id', $benefitIds)->field('job_id');
            });
        }
        //更新时间
        if( ($refreshDays=intval(array_get($params, 'refresh_days'))) > 0) {
            $query->where('refreshtime','>', time() - $refreshDays*86400);
        }

        if($q = array_get($params,'q')) {
            $query->where(function($query)use ($q) {
                $query->where('job_name','like',"%$q%");
                $query->whereOr('enterpriseinfo.company_name','like',"%$q%");
                $query->whereOr('enterpriseinfo.full_name','like',"%$q%");
            });
            try {
                if (Db::name('xilujob_search_keyword')->where('keyword', $q)->count() > 0) {
                    Db::name('xilujob_search_keyword')->where('keyword', $q)->update([
                        'search_count' => Db::raw('search_count+1')
                    ]);
                } else {
                    Db::name('xilujob_search_keyword')->insert(['keyword' => $q, 'search_count' => 1]);
                }
            }catch (\Exception $e) {
                Log::error($e->getMessage()."\n".$e->getTraceAsString());
            }
        }
        //排除黑名单企业
        if(Auth::instance()->id) {
            $query->where('publisher_id','not in', function($query) {
                $query->name('xilujob_user_blacklist_company')->where('user_id', Auth::instance()->id)->field('company_id');
            });
        }
        $query->fieldRaw($fields);
        $query->with([
            'city'=>function(Query $query){$query->withField('id,shortname as name,shortname');},
            'district'=>function(Query $query){$query->withField('id,shortname as name,shortname');},
            'town'=>function($query){$query->withField('id,name,shortname');},
            'work_experience'=>function(Query $query){$query->withField('id,name');},
            'education_level'=>function(Query $query){$query->withField('id,name');},
            'benefits'=>function(Query $query){$query->withField('id,name');},
            'enterpriseinfo'=>function(Query $query){$query->withField('id,company_name,city_id,full_name,logo');}
        ]);
        switch (array_get($params,'sort')) {
            case 1:
                //最新
                $query->order('refreshetime', 'desc');
                break;
            case 2:
                //热门
                $query->order('apply_count', 'desc');
                break;
            default:
                $query->order('job.top','desc')
                    ->order('refresh_date', 'desc')
                    ->order('apply_count', 'desc');
        }



        $pagesize = array_get($params, 'pagesize', 10);
        if($pagesize<1) {
            $pagesize = 10;
        }
        if(isset($params['city_id'])) {
            unset($params['city_id']);
        }
        $paginator = $query->paginate([
            'query' => $params, 'list_rows'=>$pagesize
        ]);
        return $paginator;
    }

    /**
     * 获取相似职位， 如果已登录，会排除黑名单公司的职位
     * @param int|Job $job
     * @return Job|\think\Paginator
     */
    public static function getSimilarJobs($job,$pagesize=10) {
        if(!$job instanceof Job) {
            $job = Job::get($job);
        }
        if(!$job) {
            return null;
        }
        $fields = 'id,publisher_id,type,job_name,job_category_id,city_id,district_id,town_id,in_hurry,direct,shop,red_packet,'.
            'red_packet_instruction,work_experience_id,education_level_id,salary_type,salary_min,salary_max,refresh_date';

        $likePath = preg_replace('/\d+,$/','',$job->job_category->path);
        //halt($likePath);
        $jobs = Job::join('XilujobJobCategory jobCategory','job.job_category_id=jobCategory.id')->where('status','1')
            ->where('black',0)
            ->where('jobCategory.path', 'like', $likePath."%")
            ->where('job.type', $job['type'])
            ->where('job.id','<>',$job->id);
        if(Auth::instance()->id) {
            $jobs->where('job.publisher_id','not in', function($query) {
                $query->name('xilujob_user_blacklist_company')->where('user_id', Auth::instance()->id)->field('company_id');
            });
        }
        $jobs = $jobs->order('apply_count','desc')
            ->order('view_count','desc')
            ->field($fields)
            ->with([
                'city'=>function( $query){$query->withField('id,name,shortname');},
                'district'=>function( $query){$query->withField('id,name,shortname');},
                'town'=>function($query){$query->withField('id,name,shortname');},
                'work_experience'=>function( $query){$query->withField('id,name');},
                'education_level'=>function( $query){$query->withField('id,name');},
                'benefits'=>function( $query){$query->withField('id,name');},
                'enterpriseinfo'=>function( $query){$query->withField('id,company_name,logo,full_name');}
            ])
            ->paginate($pagesize);
        return $jobs;
    }

    /**
     * 去除电话，qq，邮箱，微信
     * @param $content
     * @return string
     */
    private static function hide_contact($content) {
        return preg_replace('/([\d\s]{6,})|([a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+)|(微[\s]*信)|([vV][\s]*[xX])/','***',$content);
    }
}
